package info.motteke.kurumi.swt;

import static info.motteke.kurumi.swt.ColorPattern.*;
import info.motteke.kurumi.VoiceSelectedListener;
import info.motteke.kurumi.VoiceTable;
import info.motteke.mixivoice4j.User;
import info.motteke.mixivoice4j.Voice;
import info.motteke.util.MixiVoiceProperties;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

class SwtVoiceTable implements VoiceTable {

    static final Log log = LogFactory.getLog(SwtVoiceTable.class);

    private static final Comparator<Voice> DESC = new Comparator<Voice>() {
        @Override
        public int compare(Voice o1, Voice o2) {
            return -(int)(o1.getId() - o2.getId());
        }
    };

    private final MixiVoiceProperties prop = MixiVoiceProperties.getInstance();

    private final Composite parent;

    private final Table table;

    private final List<VoiceSelectedListener> listeners = new ArrayList<VoiceSelectedListener>();

    private final SwtImageCache imageCache;

    private final Map<Voice, TableItem> voice2item = new HashMap<Voice, TableItem>();

    public SwtVoiceTable(Composite parent, SwtImageCache imageCache) {
        this.parent = parent;
        this.imageCache = imageCache;
        table = initTable();
    }

    private Table initTable(){
        Table table = new Table(parent, SWT.FULL_SELECTION | SWT.BORDER);
        table.setHeaderVisible(true);
        addUserColumn(table);
        addVoiceColumn(table);
        addDateColumn(table);
        table.addSelectionListener(new TableSelectionListener(this));
        return table;
    }

    private void addUserColumn(Table table) {
        TableColumn userCol = new TableColumn(table, SWT.LEFT);
        userCol.setText("ユーザ");
        userCol.setWidth(prop.getWindowTableUserWidth());
        userCol.addControlListener(new UserColumnResizeListener(userCol));
    }

    private void addVoiceColumn(Table table) {
        TableColumn voiceCol = new TableColumn(table, SWT.LEFT);
        voiceCol.setText("つぶやき");
        voiceCol.setWidth(prop.getWindowTableVoiceWidth());
        voiceCol.addControlListener(new VoiceColumnResizeListener(voiceCol));
    }

    private void addDateColumn(Table table) {
        TableColumn dateCol = new TableColumn(table, SWT.LEFT);
        dateCol.setText("日時");
        dateCol.setWidth(prop.getWindowTableDateWidth());
        dateCol.addControlListener(new DateColumnResizeListener(dateCol));
    }

    /* (非 Javadoc)
     * @see info.motteke.kurumi.swt.VoiceTable#addVoice(java.util.List)
     */
    public void addVoice(Collection<Voice> voices) {
        final List<Voice> list = new ArrayList<Voice>(voices);
        Collections.sort(list, DESC);
        log.info(voices.size() + "件のつぶやきを追加します。");
        table.getDisplay().asyncExec(new VoiceAppender(this, list, imageCache));

    }

    public Table getTable() {
        return table;
    }

    /* package */ void addItem(Voice voice, TableItem item) {
        voice2item.put(voice, item);
    }

    @Override
    public void addVoiceSelectedListener(VoiceSelectedListener listener) {
        listeners.add(listener);
    }

    public List<VoiceSelectedListener> getListeners() {
        return listeners;
    }
}

class UserColumnResizeListener extends ControlAdapter {

    private final TableColumn col;

    private final MixiVoiceProperties prop;

    public UserColumnResizeListener(TableColumn column){
        this.col = column;
        prop = MixiVoiceProperties.getInstance();
    }

    @Override
    public void controlResized(ControlEvent e) {
        prop.setWindowTableUserWidth(col.getWidth());
    }
}

class VoiceColumnResizeListener extends ControlAdapter {

    private final TableColumn col;

    private final MixiVoiceProperties prop;

    public VoiceColumnResizeListener(TableColumn column) {
        this.col = column;
        prop = MixiVoiceProperties.getInstance();
    }

    @Override
    public void controlResized(ControlEvent e) {
        prop.setWindowTableVoiceWidth(col.getWidth());
    }
}

class DateColumnResizeListener extends ControlAdapter {
    private final TableColumn col;

    private final MixiVoiceProperties prop;

    public DateColumnResizeListener(TableColumn column) {
        this.col = column;
        prop = MixiVoiceProperties.getInstance();
    }

    @Override
    public void controlResized(ControlEvent e) {
        prop.setWindowTableDateWidth(col.getWidth());
    }
}


class TableSelectionListener extends SelectionAdapter {
    private final SwtVoiceTable voiceTable;

    public TableSelectionListener(SwtVoiceTable table) {
        this.voiceTable = table;
    }

    @Override
    public void widgetSelected(SelectionEvent e) {
        Table table = voiceTable.getTable();
        int index = table.getSelectionIndex();

        TableItem selection = table.getItem(index);

        Voice selectedVoice = (Voice) selection.getData();

        for (VoiceSelectedListener listener : voiceTable.getListeners()) {
            listener.onTableVoiceSelected(selectedVoice);
        }

        for (TableItem item : table.getItems()) {
            Voice voice = (Voice) item.getData();
            User user = voice.getUser();
            if (voice.getParent().equals(selectedVoice.getParent())) {
                item.setBackground(LIGHT_PINK);
            } else if (user.equals(selectedVoice.getUser())) {
                item.setBackground(YELLOW);
            } else {
                item.setBackground(WHITE);
            }
        }
    }
}
